﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Web.Mvc;

namespace WebStudio.Mvc.Core.Extensions
{
    /// <summary>
    /// jquery插件中的treeview控件的帮助类，用于生成treeview控件所需要的html代码结构
    /// </summary>
    public static class TreeViewExtension
    {
        #region TreeView扩展 重载
        /// <summary>
        /// Create a TreeView of nodes starting from a root element
        /// </summary>
        /// <param name="html"></param>
        /// <param name="treeId">The ID that will be used when the ul is created</param>
        /// <param name="datas">The root nodes to create</param>
        /// <param name="_Childs">A lambda expression that returns the children nodes</param>
        /// <param name="_ItemContent">A lambda expression defining the content in each tree node</param>
        public static string TreeView<T>(this HtmlHelper html, string treeId, IEnumerable<T> datas, IEnumerable<T> roots, Func<T, IEnumerable<T>> _Childs, Func<T, string> _ItemContent)
        {
            TreeViewOptions<T> options = new TreeViewOptions<T>();
            return html.TreeView(treeId, datas, roots, _Childs, _ItemContent, options);
        }
        #endregion

        #region TreeView扩展 重载
        /// <summary>
        /// Create a TreeView of nodes starting from a root element
        /// </summary>
        /// <param name="html"></param>
        /// <param name="treeId">The ID that will be used when the ul is created</param>
        /// <param name="datas">The root nodes to create</param>
        /// <param name="_Childs">A lambda expression that returns the children nodes</param>
        /// <param name="_ItemContent">A lambda expression defining the content in each tree node</param>
        /// <param name="_Expand">是否展开</param>
        public static string TreeView<T>(this HtmlHelper html, string treeId, IEnumerable<T> datas, IEnumerable<T> roots, Func<T, IEnumerable<T>> _Childs, Func<T, string> _ItemContent, Func<T, bool> _Expand)
        {
            TreeViewOptions<T> options = new TreeViewOptions<T>();
            options.Expand = _Expand;
            return html.TreeView(treeId, datas, roots, _Childs, _ItemContent, options);
        }
        #endregion

        #region TreeView扩展 重载
        /// <summary>
        /// Create a TreeView of nodes starting from a root element
        /// </summary>
        /// <param name="html"></param>
        /// <param name="treeId">The ID that will be used when the ul is created</param>
        /// <param name="datas">The root nodes to create</param>
        /// <param name="_Childs">A lambda expression that returns the children nodes</param>
        /// <param name="_ItemContent">A lambda expression defining the content in each tree node</param>
        /// <param name="includeScript">If true, output will automatically render the JavaScript to turn the ul into the treeview</param>    
        /// <param name="_Expand"></param>    
        /// <param name="_IDRule">If true, output will automatically render the JavaScript to turn the ul into the treeview</param>    
        public static string TreeView<T>(this HtmlHelper html, string treeId, IEnumerable<T> datas, IEnumerable<T> roots, Func<T, IEnumerable<T>> _Childs, Func<T, string> _ItemContent, Func<T, bool> _Expand, Func<T, string> _IDRule)
        {
            TreeViewOptions<T> options = new TreeViewOptions<T>();
            options.Expand = _Expand;
            options.IDRule = _IDRule;
            return html.TreeView(treeId, datas, roots, _Childs, _ItemContent, options);
        }
        #endregion

        #region TreeView扩展 重载
        /// <summary>
        /// Create a TreeView of nodes starting from a root element
        /// </summary>
        /// <param name="html"></param>
        /// <param name="treeId">The ID that will be used when the ul is created</param>
        /// <param name="datas">The root nodes to create</param>
        /// <param name="_Childs">A lambda expression that returns the children nodes</param>
        /// <param name="_ItemContent">A lambda expression defining the content in each tree node</param>
        /// <param name="_IDRule">生成项标识函数</param>    
        /// <param name="includeScript">If true, output will automatically render the JavaScript to turn the ul into the treeview</param>    
        public static string TreeView<T>(this HtmlHelper html, string treeId, IEnumerable<T> datas, IEnumerable<T> roots, Func<T, IEnumerable<T>> _Childs, Func<T, string> _ItemContent, Func<T, bool> _Expand, Func<T, string> _IDRule, bool includeScript)
        {
            TreeViewOptions<T> options = new TreeViewOptions<T>();
            options.Expand = _Expand;
            options.IDRule = _IDRule;
            options.IncludeScript = includeScript;
            return html.TreeView(treeId, datas,roots, _Childs, _ItemContent, options);
        }
        #endregion

        #region TreeView扩展
        /// <summary>
        /// Create a TreeView of nodes starting from a root element
        /// </summary>
        /// <param name="html"></param>
        /// <param name="treeId">The ID that will be used when the ul is created</param>
        /// <param name="datas">所有数据</param>
        /// <param name="_Childs">A lambda expression that returns the children nodes</param>
        /// <param name="_ItemContent">A lambda expression defining the content in each tree node</param>
        /// <param name="options">参数</param>
        public static string TreeView<T>(this HtmlHelper html, string treeId, IEnumerable<T> datas, IEnumerable<T> roots, Func<T, IEnumerable<T>> _Childs, Func<T, string> _ItemContent, TreeViewOptions<T> options)
        {
            StringBuilder sb = new StringBuilder();

            sb.AppendFormat("<ul id='{0}'>\r\n", treeId);

            if (datas.Count() == 0)
            {
                sb.AppendFormat("<li>{0}</li>", options.EmptyDesc);
            }

            foreach (T item in roots)
            {
                //呈现节点
                RenderLi(sb, item, _ItemContent, options);


                //呈现子节点
                AppendChildren(sb, item, _Childs, _ItemContent, options);
            }

            sb.AppendLine("</ul>");

            if (options.IncludeScript)
            {
                sb.AppendFormat(
                    @"<script type='text/javascript'>
                    $(document).ready(function() {{
                        $('#{0}').treeview({{ animated: 'fast',unique:true }});
                    }});
                </script>", treeId);
            }

            return sb.ToString();
        }
        #endregion


        #region 呈现子节点函数
        /// <summary>
        /// 呈现子节点函数
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="builder"></param>
        /// <param name="item"></param>
        /// <param name="_Childs"></param>
        /// <param name="_ItemContent"></param>
        /// <param name="options">参数</param>
        private static void AppendChildren<T>(StringBuilder builder, T item, Func<T, IEnumerable<T>> _Childs, Func<T, string> _ItemContent, TreeViewOptions<T> options)
        {
            var childs = _Childs(item);
            if (childs.Count() == 0)
            {
                builder.AppendLine("</li>");
                return;
            }

            builder.AppendLine("\r\n<ul>");
            foreach (T child in childs)
            {
                //呈现当前节点
                RenderLi(builder, child, _ItemContent, options);

                //递归呈现子节点
                AppendChildren(builder, child, _Childs, _ItemContent, options);
            }

            builder.AppendLine("</ul></li>");
        }
        #endregion

        #region 呈现当前节点函数
        /// <summary>
        /// 呈现当前节点函数
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="sb"></param>
        /// <param name="item"></param>
        /// <param name="_ItemContent"></param>
        /// <param name="options">参数</param>
        private static void RenderLi<T>(StringBuilder sb, T item, Func<T, string> _ItemContent, TreeViewOptions<T> options)
        {
            bool expand = options.Expand != null && options.Expand(item);
            string id = options.IDRule != null ? string.Format("id='{0}'", options.IDRule(item)) : string.Empty;
            sb.AppendFormat("<li {2} {1}>{0}", _ItemContent(item), expand ? "" : "class='closed' ", id);
        }
        #endregion
    }

    /// <summary>
    /// 参数
    /// </summary>
    public class TreeViewOptions<T>
    {
        public TreeViewOptions()
        {
            EmptyDesc = string.Empty;
            IncludeScript = true;
        }

        /// <summary>
        /// 是否展开函数
        /// </summary>
        public Func<T, bool> Expand { get; set; }

        /// <summary>
        /// 标识命名函数
        /// </summary>
        public Func<T, string> IDRule { get; set; }

        /// <summary>
        /// 是否包含初始化脚本
        /// </summary>
        public bool IncludeScript { get; set; }

        /// <summary>
        /// 空数据时呈现描述
        /// </summary>
        public string EmptyDesc { get; set; }
    }
}
